// ICC-AVR application builder : 2022/5/16 22:59:09
//  Target : M2560
//  Crystal: 16.000Mhz

#include <iom2560v.h>
#include <macros.h>
#include <stdio.h>
#include <string.h>
#include "timer.h"
#include "board.h"
#include "i2c.h"
#include "key.h"
#include "OLEDWork.h"

#define seg595_OE_port PA
#define seg595_OE_pin 6
#define seg595_ST_port PA
#define seg595_ST_pin 4

#define dz595_OE_port PA
#define dz595_OE_pin 7
#define dz595_ST_port PA
#define dz595_ST_pin 5

#define DIR_UP 0
#define DIR_DOWN 1
#define DIR_LEFT 2
#define DIR_RIGHT 3

#define SEG_ST_CLK()       \
    gpioWrite(PA, 4, LOW); \
    gpioWrite(PA, 4, HIGH)
#define DZ_ST_CLK()        \
    gpioWrite(PA, 5, LOW); \
    gpioWrite(PA, 5, HIGH)

unsigned char Led_7[16] = {0xFC, 0x60, 0xDA, 0xF2, 0x66, 0xB6, 0xBE, 0xE0, 0xFE, 0xF6};

unsigned char Disp_data[4] = {0, 0, 0, 0};

U8 Voice_01_Arr[] = {0xAA, 0x1B, 0x02, 0x30, 0x31, 0x28};
U8 Voice_02_Arr[] = {0xAA, 0x1B, 0x02, 0x30, 0x32, 0x29};
U8 Voice_03_Arr[] = {0xAA, 0x1B, 0x02, 0x30, 0x33, 0x2A};
U8 Voice_04_Arr[] = {0xAA, 0x1B, 0x02, 0x30, 0x34, 0x2B};
U8 Voice_05_Arr[] = {0xAA, 0x1B, 0x02, 0x30, 0x35, 0x2C};
U8 Voice_06_Arr[] = {0xAA, 0x1B, 0x02, 0x30, 0x36, 0x2D};
U8 Voice_07_Arr[] = {0xAA, 0x1B, 0x02, 0x30, 0x37, 0x2E};
U8 Voice_08_Arr[] = {0xAA, 0x1B, 0x02, 0x30, 0x38, 0x2F};
U8 Voice_09_Arr[] = {0xAA, 0x1B, 0x02, 0x30, 0x39, 0x30};
U8 Voice_10_Arr[] = {0xAA, 0x1B, 0x02, 0x31, 0x30, 0x28};
U8 Voice_11_Arr[] = {0xAA, 0x1B, 0x02, 0x31, 0x31, 0x29};
U8 Voice_12_Arr[] = {0xAA, 0x1B, 0x02, 0x31, 0x32, 0x2A};
U8 Voice_13_Arr[] = {0xAA, 0x1B, 0x02, 0x31, 0x33, 0x2B};
U8 Voice_14_Arr[] = {0xAA, 0x1B, 0x02, 0x31, 0x34, 0x2C};
U8 Voice_15_Arr[] = {0xAA, 0x1B, 0x02, 0x31, 0x35, 0x2D};
U8 Voice_16_Arr[] = {0xAA, 0x1B, 0x02, 0x31, 0x36, 0x2E};
U8 Voice_17_Arr[] = {0xAA, 0x1B, 0x02, 0x31, 0x37, 0x2F};
U8 Voice_18_Arr[] = {0xAA, 0x1B, 0x02, 0x31, 0x38, 0x30};
U8 Voice_19_Arr[] = {0xAA, 0x1B, 0x02, 0x31, 0x39, 0x31};
U8 Voice_20_Arr[] = {0xAA, 0x1B, 0x02, 0x32, 0x30, 0x29};

int delay_count = 50;
int now_count = 0;

int buzz_count_double = 0; // 蜂鸣器响应计数双倍

// 总分
int all_score = 0;

// 贪吃蛇长度
int snake_len = 4;

// 蛇的理论存活标记
int snake_alive_normal = 1;

// 是否正在运行(对标暂停状态)
int isRunning = 1;

// 是否开启穿墙模式
int is_cross_wall_on = 0;

// 是否开启AI自动模式
int is_ai_on = 0;

// 是否发出声音
int is_sound_on = 1;

// 是否开启停靠模式
int isKeepMolde = 0;

// 贪吃蛇数组
int snake_arr[512][2] = {0};

// 两个蜂鸣器响应计数间隔
int two_buzz_count_need = 5000;

// 当前食物是否存在
int food_exist = 0;

// 当前食物的位置
int food_pox_x = -1;
int food_pox_y = -1;

// 尾部增长状态
int tail_grow_state = 0;

// 当前方向
int Snack_Dir = 3;

// //AI预测方向数组
// int ai_dir_arr[100] = {0};

// //AI预测长总度
// int ai_all_len=0;

// //AI当前步下标
// int ai_now_index=0;

// 当前蛇头与食物x差距
int head_to_food_graph_x = 0;
int head_to_food_graph_y = 0;

int isOnce = 1;

int is_real_Die_Once = 1;
int is_Lcd_Run = 1;
int lcd_run_count = 800000;

// 游戏地图xy为坐标
char game_Map[32][16] = {
    // 方便可视化
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
};

unsigned char zdhz[][32] = {
    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
};

// //深度搜索
// void ai_depth_search(int snake_head_x, int snake_head_y,int deep_count)
// {
//     for(int i=0;i<4;i++){
//         switch (i)
//         {
//         case 0:
//             if(ai)
//             break;
//         }
//     }
// }

// //ai计算路径
// int ai_path_calc()
// {
//     int snake_head_x = snake_arr[0][0];
//     int snake_head_y = snake_arr[0][1];

//     ai_depth_search(snake_head_x, snake_head_y, 0);
// }

// AI补丁
void ai_path_patch(int caseType, int *dir_pre_arr, int snake_head_x, int snake_head_y)
{
    // printf("[%d,%d,%d]\n", snake_head_x, snake_head_y, caseType);

    switch (caseType)
    {
    case 0:
        if (snake_len == 91)
        {
            if (snake_head_x == 9 && snake_head_y == 4)
            {
                dir_pre_arr[0] = DIR_DOWN;
                dir_pre_arr[1] = DIR_UP;
                dir_pre_arr[2] = DIR_RIGHT;
                dir_pre_arr[3] = DIR_LEFT;
            }
        }
        break;
    case 1:
        if (snake_len == 63)
        {
            dir_pre_arr[0] = DIR_RIGHT;
            dir_pre_arr[1] = DIR_DOWN;
            dir_pre_arr[2] = DIR_UP;
            dir_pre_arr[3] = DIR_LEFT;
        }
        else if (snake_len == 71)
        {
            // printf("[%d,%d,%d]\n", snake_head_x, snake_head_y, caseType);
            if (snake_head_x == 10 && snake_head_y == 9)
            {
                dir_pre_arr[0] = DIR_UP;
                dir_pre_arr[1] = DIR_RIGHT;
                dir_pre_arr[2] = DIR_LEFT;
                dir_pre_arr[3] = DIR_DOWN;
            }
        }
        else if (snake_len == 74)
        {
            if (snake_head_x == 9 && snake_head_y == 8)
            {
                dir_pre_arr[0] = DIR_RIGHT;
                dir_pre_arr[1] = DIR_UP;
                dir_pre_arr[2] = DIR_LEFT;
                dir_pre_arr[3] = DIR_DOWN;
            }
        }
        else if (snake_len == 98)
        {
            if (snake_head_x == 26 && snake_head_y == 14)
            {
                dir_pre_arr[0] = DIR_UP;
                dir_pre_arr[1] = DIR_LEFT;
                dir_pre_arr[2] = DIR_DOWN;
                dir_pre_arr[3] = DIR_RIGHT;
            }
        }

        break;
    case 2:
        if (snake_len == 85)
        {
            if (snake_head_x == 18 && snake_head_y == 7)
            {
                dir_pre_arr[0] = DIR_UP;
                dir_pre_arr[1] = DIR_RIGHT;
                dir_pre_arr[2] = DIR_DOWN;
                dir_pre_arr[3] = DIR_LEFT;
            }
        }
        break;
    case 3:

        break;
    default:
        break;
    }
}

// 遍历AI预设方向
void try_ai_pre_dirs(int *dir_pre_arr, int head_x, int head_y)
{
    int i;
    int head_pre_x = head_x;
    int head_pre_y = head_y;

    for (i = 0; i < 4; i++)
    {
        switch (dir_pre_arr[i])
        {
        case DIR_UP:
            if (Snack_Dir == DIR_DOWN)
                continue;
            head_y++;
            if (head_y == 16)
            {
                if (is_cross_wall_on == 1)
                {
                    head_y = 0;
                }
            }

            if (head_y >= 0 && head_y < 16)
            {
                if (game_Map[head_x][head_y] == 0 || (head_x == food_pox_x && head_y == food_pox_y))
                {
                    Snack_Dir = DIR_UP;
                    head_y = head_pre_y;
                    return;
                }
            }
            head_y = head_pre_y;
            break;
        case DIR_DOWN:

            if (Snack_Dir == DIR_UP)
                continue;
            head_y--;

            if (head_y < 0)
            {
                if (is_cross_wall_on == 1)
                {
                    head_y = 15;
                }
            }

            if (head_y >= 0 && head_y < 16)
            {
                if (game_Map[head_x][head_y] == 0 || (head_x == food_pox_x && head_y == food_pox_y))
                {
                    Snack_Dir = DIR_DOWN;
                    head_y = head_pre_y;
                    return;
                }
            }
            head_y = head_pre_y;
            break;
        case DIR_LEFT:
            if (Snack_Dir == DIR_RIGHT)
            {
                continue;
            }
            head_x--;
            if (head_x < 0)
            {
                if (is_cross_wall_on == 1)
                {
                    head_x = 31;
                }
            }

            if (head_x >= 0 && head_x < 32)
            {
                if (game_Map[head_x][head_y] == 0 || (head_x == food_pox_x && head_y == food_pox_y))
                {
                    Snack_Dir = DIR_LEFT;
                    head_x = head_pre_x;
                    return;
                }
            }
            head_x = head_pre_x;
            break;
        case DIR_RIGHT:
            if (Snack_Dir == DIR_LEFT)
                continue;
            head_x++;
            if (head_x == 32)
            {
                if (is_cross_wall_on == 1)
                {
                    head_x = 0;
                }
            }
            if (head_x >= 0 && head_x < 32)
            {
                if (game_Map[head_x][head_y] == 0 || (head_x == food_pox_x && head_y == food_pox_y))
                {
                    Snack_Dir = DIR_RIGHT;
                    head_x = head_pre_x;
                    return;
                }
            }
            head_x = head_pre_x;
            break;
        default:
            break;
        }
    }

    if (is_real_Die_Once == 1)
    {
        if (is_sound_on == 1)
        {
            UART1_send(Voice_17_Arr, 6);
        }
        is_real_Die_Once = 0;
    }

    printf("no path\n");
    printf("[%d,%d]\n", snake_arr[0][0], snake_arr[1][0]);

    // die
    snake_alive_normal = 0;
    buzz_count_double = two_buzz_count_need;
}

// ai修改方向
void ai_fix_dir()
{
    int snake_next_x, snake_next_y;
    int dir_pre_arr[4] = {0};
    int snake_head_x = snake_arr[0][0];
    int snake_head_y = snake_arr[0][1];
    int caseType = 0;

    head_to_food_graph_x = food_pox_x - snake_head_x;
    head_to_food_graph_y = food_pox_y - snake_head_y;

    // printf("\r\n----%d,%d----", head_to_food_graph_x, head_to_food_graph_y);

    if (head_to_food_graph_x >= 0 && head_to_food_graph_y >= 0) // 右上
    {
        dir_pre_arr[0] = 0; // 上
        dir_pre_arr[1] = 3; // 右
        dir_pre_arr[2] = 2; // 左
        dir_pre_arr[3] = 1; // 下
        caseType = 0;
    }
    else if (head_to_food_graph_x <= 0 && head_to_food_graph_y <= 0) // 左下
    {
        // printf("\r\n---- %d,%d----\r\n", head_to_food_graph_x, head_to_food_graph_y);
        //   printf("---left bottom----\r\n");
        dir_pre_arr[0] = 2; // 左
        dir_pre_arr[1] = 1; // 下
        dir_pre_arr[2] = 0; // 上
        dir_pre_arr[3] = 3; // 右
        caseType = 1;
    }
    else if (head_to_food_graph_x > 0) // 右下
    {
        dir_pre_arr[0] = 3; // 右
        dir_pre_arr[1] = 1; // 下
        dir_pre_arr[2] = 2; // 左
        dir_pre_arr[3] = 0; // 上
        caseType = 2;
    }
    else // 左上
    {
        dir_pre_arr[0] = 0; // 上
        dir_pre_arr[1] = 2; // 左
        dir_pre_arr[2] = 3; // 右
        dir_pre_arr[3] = 1; // 下
        caseType = 3;
    }

    ai_path_patch(caseType, dir_pre_arr, snake_head_x, snake_head_y);

    try_ai_pre_dirs(dir_pre_arr, snake_head_x, snake_head_y);

    // printf("\r\n----%d\r\n", Snack_Dir);
}

// 分数每一位转数组
void Score_To_Arr()
{
    Disp_data[3] = all_score % 10;
    Disp_data[2] = all_score / 10 % 10;
    Disp_data[1] = all_score / 100 % 10;
    Disp_data[0] = all_score / 1000 % 10;
}

// map小单元转zdhz
void map_unit_To_zdhz(int *arr, int count)
{

    int unit_first = 0, unit_second = 0;
    int i = 0;
    unsigned char result_chars = 0;

    for (i = 7; i >= 0; i--)
    {
        // if(arr[i]==1){
        //       printf("hhh:%d\r\n",count);
        // }

        result_chars <<= 1;
        if (arr[i] == 1)
        {
            result_chars |= 1;
        }
    }

    // printf("hhh:%d\r\n",count);
    // printf("0x%02X\r\n", result_chars);
    zdhz[count / 32][count % 32] = result_chars;
}

// map转zdhz
void map_To_zdhz()
{

    int i, j;

    int count = 0; // 单元次数

    int unit_arr[8] = {0}; // 单元数组
    int unit_index = 0;    // 单元数组下标
    int unit_count = 0;    // 每8个一个单元
    int i_start = 0, i_end = 8;

    for (j = 15; j >= 0; j--)
    {
        for (i = i_start; i < i_end; i++)
        {

            unit_arr[unit_index] = game_Map[i][j];
            unit_index++;
            if (unit_index == 8)
            {
                unit_index = 0;
                // printf("%d\r\n", unit_arr);
                //  printf("%d\r\n", count);
                // 转换为十六进制并传入zdhz数组中

                map_unit_To_zdhz(unit_arr, count);
                count++;
            }
        }

        if (j == 0 && i_end != 32)
        {
            i_start += 8;
            i_end += 8;
            j = 16;
        }
    }
}

// 渲染函数
void render_Screen()
{
    map_To_zdhz();
}

// 当前位置是否在贪吃蛇之上
char is_On_Snake(char x, char y)
{
    char i;
    for (i = 0; i < snake_len; i++)
    {
        if (snake_arr[i][0] == x && snake_arr[i][1] == y)
        {
            return 1;
        }
    }
    return 0;
}

// 随机生成食物
void randomFood()
{
    char i = 0, j = 0;

    while (i == 0 || i == 31 || j == 0 || j == 15 || is_On_Snake(i, j) == 1)
    {
        i = rand() % 31;
        j = rand() % 15;
    }

    food_pox_x = i;
    food_pox_y = j;

    game_Map[i][j] = 1;
}

// 是否到达delay_count
char is_Arrive_Delay_count()
{
    if (delay_count == now_count)
    {
        now_count = 0;
        return 1;
    }
    return 0;
}

// 打印蛇的数组
void print_Snake_arr()
{
    char i;
    printf("snake_arr:-----------------------------------\n");

    for (i = 0; i < snake_len; i++)
    {
        printf("[%d,%d]\n", snake_arr[i][0], snake_arr[i][1]);
    }
}

void print_Map()
{

    char i, j;

    printf("game_Map:-----------------------------------\n");
    for (i = 0; i < 16; i++)
    {
        for (j = 0; j < 32; j++)
        {
            printf("%d", game_Map[j][i]);
        }
        printf("\n");
    }
}

// 蛇是否咬到自己
char is_Snake_Bite_Itself(int next_x, int next_y)
{
    char i;
    for (i = 1; i < snake_len; i++)
    {
        if (next_x == snake_arr[i][0] && next_y == snake_arr[i][1])
        {
            return 1;
        }
    }
    return 0;
}

// 蛇自行移动操作数组
void move_Snake_toChange_data(int dir)
{
    char head_x = snake_arr[0][0];
    char head_y = snake_arr[0][1];
    char i = 0;

    dir = Snack_Dir;
    // printf("----dir:%d\n", dir);
    if (tail_grow_state == 0)
    {
        game_Map[snake_arr[snake_len - 1][0]][snake_arr[snake_len - 1][1]] = 0;
    }
    else
    {
        snake_len++;
        snake_arr[snake_len][0] = snake_arr[snake_len - 1][0];
        snake_arr[snake_len][1] = snake_arr[snake_len - 1][1];
        tail_grow_state = 0;
    }

    // 打印蛇的长度
    //  printf("snake_len:%d\n", snake_len);

    // 打印灭的坐标
    //  printf("--:[%d,%d]\n", snake_arr[snake_len-1][0], snake_arr[snake_len-1][1]);

    for (i = snake_len; i > 0; i--)
    {
        snake_arr[i][0] = snake_arr[i - 1][0];
        snake_arr[i][1] = snake_arr[i - 1][1];
    }

    switch (dir)
    {
    case DIR_UP:
        snake_arr[0][0] = head_x;
        snake_arr[0][1] = head_y + 1;
        head_y++;
        if (head_y == 16)
        {
            head_y = 0;
            snake_arr[0][1] = 0;
        }
        break;
    case DIR_DOWN:
        snake_arr[0][0] = head_x;
        snake_arr[0][1] = head_y - 1;
        head_y--;
        if (head_y == -1)
        {
            head_y = 15;
            snake_arr[0][1] = 15;
        }
        break;
    case DIR_LEFT:
        snake_arr[0][0] = head_x - 1;
        snake_arr[0][1] = head_y;
        head_x--;
        if (head_x == -1)
        {
            head_x = 31;
            snake_arr[0][0] = 31;
        }
        break;
    case DIR_RIGHT:
        snake_arr[0][0] = head_x + 1;
        snake_arr[0][1] = head_y;
        head_x++;
        if (head_x == 32)
        {
            head_x = 0;
            snake_arr[0][0] = 0;
        }
        break;
    }

    game_Map[head_x][head_y] = 1;

    // 打印亮的坐标
    //  printf("+++:[%d,%d]\n", head_x, head_y);

    //  print_Snake_arr();
    // print_Map();
}

// 获取蛇预测下一个x位置
int getNextX(int now_x)
{
    switch (Snack_Dir)
    {
    case DIR_LEFT:
        if (now_x == 0)
            return 31;
        return now_x - 1;
        break;
    case DIR_RIGHT:
        if (now_x == 31)
            return 0;
        return now_x + 1;
        break;
    default:
        break;
    }
}

// 获取蛇预测下一个y位置
int getNextY(int now_y)
{
    switch (Snack_Dir)
    {
    case DIR_UP:
        if (now_y == 15)
            return 0;
        return now_y + 1;
        break;
    case DIR_DOWN:
        if (now_y == 0)
            return 15;
        return now_y - 1;
        break;
    default:
        break;
    }
}

int is_die_real(int preview_x, int preview_y)
{
    int i = 0;
    int now_x = 0, now_y = 0;
    int dir_arr[4][2] = {
        {1, 1},
        {1, -1},
        {-1, 1},
        {-1, -1}};
    for (i = 0; i < 4; i++)
    {
        now_x = preview_x + dir_arr[i][0];
        now_y = preview_y + dir_arr[i][1];

        if (now_x == -1)
        {
            now_x = 31;
        }
        else if (now_x == 32)
        {
            now_x = 0;
        }
        else if (now_y == -1)
        {
            now_y = 15;
        }
        else if (now_y == 16)
        {
            now_y = 0;
        }

        if (game_Map[now_x][now_y] == 0)
        {
            return 0;
        }
    }

    return 1;
}

void die_voice_case(int preview_x, int preview_y)
{

    if (is_die_real(preview_x, preview_y) == 1)
    {
        if (is_real_Die_Once == 1)
        {
            if (is_sound_on == 1)
            {
                UART1_send(Voice_17_Arr, 6);
            }
            is_real_Die_Once = 0;
        }

        return;
    }

    if (isKeepMolde)
    {

        if (isOnce == 1)
        {
            if (is_sound_on == 1)
            {
                UART1_send(Voice_15_Arr, 6);
            }
            if (isOnce == 1)
            {
                isOnce = 0;
            }
        }
    }
    else
    {
        if (is_sound_on == 1)
        {
            UART1_send(Voice_16_Arr, 6);
        }
        isOnce = 1;
    }
}

// 蛇自行移动
void move_Opt()
{

    int preview_x = snake_arr[0][0];
    int preview_y = snake_arr[0][1];

    int next_x = getNextX(preview_x);
    int next_y = getNextY(preview_y);

    if (is_ai_on == 1)
    {
        ai_fix_dir();
    }

    if (snake_alive_normal == 0 && is_ai_on == 1)
    {
        printf("snake_len:%d\n", snake_len);
        return;
    }
    switch (Snack_Dir)
    {
    case DIR_UP:
        // isOnce = 1;
        if (((preview_y == 15 && (is_cross_wall_on == 0)) || is_Snake_Bite_Itself(next_x, next_y) == 1) && (is_ai_on == 0))
        {
            // die
            snake_alive_normal = 0;
            buzz_count_double = two_buzz_count_need;
            die_voice_case(preview_x, preview_y);
        }
        else
        {
            snake_alive_normal = 1;
            buzz_count_double = 0;
            move_Snake_toChange_data(DIR_UP);
        }
        break;
    case DIR_DOWN:
        // isOnce = 1;
        if (((preview_y == 0 && (is_cross_wall_on == 0)) || is_Snake_Bite_Itself(next_x, next_y) == 1) && (is_ai_on == 0))
        {
            // die
            snake_alive_normal = 0;
            buzz_count_double = two_buzz_count_need;
            die_voice_case(preview_x, preview_y);
        }
        else
        {
            snake_alive_normal = 1;
            buzz_count_double = 0;
            move_Snake_toChange_data(DIR_DOWN);
        }
        break;
    case DIR_LEFT:
        // isOnce = 1;
        if (((preview_x == 0 && (is_cross_wall_on == 0)) || is_Snake_Bite_Itself(next_x, next_y) == 1) && (is_ai_on == 0))
        {
            // die
            snake_alive_normal = 0;
            buzz_count_double = two_buzz_count_need;
            die_voice_case(preview_x, preview_y);
        }
        else
        {
            snake_alive_normal = 1;
            buzz_count_double = 0;
            move_Snake_toChange_data(DIR_LEFT);
        }
        break;
    case DIR_RIGHT:
        // isOnce = 1;
        if (((preview_x == 31 && (is_cross_wall_on == 0)) || is_Snake_Bite_Itself(next_x, next_y) == 1) && (is_ai_on == 0))
        {
            // die
            snake_alive_normal = 0;
            buzz_count_double = two_buzz_count_need;
            die_voice_case(preview_x, preview_y);
        }
        else
        {
            snake_alive_normal = 1;
            buzz_count_double = 0;
            move_Snake_toChange_data(DIR_RIGHT);
        }
        break;
    default:
        printf("error dir\n");
    }
}

// 初始化蛇
void init_Snake()

{
    snake_arr[0][0] = 3;
    snake_arr[0][1] = 8;

    snake_arr[1][0] = 2;
    snake_arr[1][1] = 8;

    snake_arr[2][0] = 1;
    snake_arr[2][1] = 8;

    snake_arr[3][0] = 0;
    snake_arr[3][1] = 8;

    game_Map[3][8] = 1;
    game_Map[2][8] = 1;
    game_Map[1][8] = 1;
    game_Map[0][8] = 1;
}
// 加速
void addSpeed()
{
    if (delay_count == 1)
    {
        printf("renew normal speed\n");
    }
    if (delay_count > 10)
    {

        if (is_sound_on == 1)
        {
            UART1_send(Voice_06_Arr, 6);
        }
        delay_count -= 10;

        now_count = 0;
        printf("addSpeed\n");
    }
    else
    {
        if (is_sound_on == 1)
        {
            UART1_send(Voice_18_Arr, 6);
        }
        printf("addSpeed max\n");
    }
    if (is_sound_on == 1)
    {
        // buzzWorkOnce();
    }
}

// 减速
void minusSpeed()
{
    if (delay_count < 100)
    {
        if (is_sound_on == 1)
        {
            UART1_send(Voice_05_Arr, 6);
        }
        delay_count += 10;

        now_count = 0;
        printf("minusSpeed\n");
    }
    else
    {
        if (is_sound_on == 1)
        {
            UART1_send(Voice_19_Arr, 6);
        }
        printf("minusSpeed min\n");
    }
    if (is_sound_on == 1)
    {
        // buzzWorkOnce();
    }
}

// 切换暂停状态
void pauseGame()
{
    printf("\n");
    if (is_sound_on == 1)
    {
        // buzzWorkOnce();
    }
    if (isRunning == 1)
    {
        if (is_sound_on == 1)
        {
            UART1_send(Voice_02_Arr, 6);
        }
        isRunning = 0;
        printf("pause\n");
    }
    else
    {
        if (is_sound_on == 1)
        {
            UART1_send(Voice_03_Arr, 6);
        }
        isRunning = 1;
        printf("continue\n");
    }
}

// 控制蛇的方向
void move_control(int dir)
{
    switch (dir)
    {
    case K1_2: // up
        isOnce = 1;
        if (Snack_Dir != DIR_DOWN)
            Snack_Dir = DIR_UP;
        break;
    case K2_2: // down
        isOnce = 1;
        if (Snack_Dir != DIR_UP)
            Snack_Dir = DIR_DOWN;
        break;
    case K2_1: // left
        isOnce = 1;
        if (Snack_Dir != DIR_RIGHT)
            Snack_Dir = DIR_LEFT;
        break;
    case K2_3: // right
        isOnce = 1;
        if (Snack_Dir != DIR_LEFT)
            Snack_Dir = DIR_RIGHT;
        break;
    default:
        break;
    }
}

// 重置游戏地图状态
void reset_Map()
{
    int i, j;
    for (i = 0; i < 32; i++)
    {
        for (j = 0; j < 16; j++)
        {
            game_Map[i][j] = 0;
        }
    }
}

// 重新开始
void restartGame()
{
    int i = 0;
    if (is_sound_on == 1)
    {
        UART1_send(Voice_04_Arr, 6);
    }
    reset_Map();
    init_Snake();
    isOnce = 1;
    all_score = 0;
    snake_len = 4;
    snake_alive_normal = 1;
    isRunning = 1;
    food_exist = 0;
    tail_grow_state = 0;
    Snack_Dir = 3;
    is_real_Die_Once = 1;
    for (i = 0; i < 4; i++)
    {
        Disp_data[i] = 0;
    }
    Score_To_Arr();
    update_oled_mess();
}

// 设置静音状态
void changeSoundState()
{
    if (is_sound_on == 0)
    {
        UART1_send(Voice_09_Arr, 6);
        is_sound_on = 1;
        printf("open sound\n");
    }
    else
    {
        UART1_send(Voice_10_Arr, 6);
        is_sound_on = 0;
        printf("close sound\n");
    }
}

// 设置是否穿墙
void changeCrossWallState()
{
    if (is_cross_wall_on == 0)
    {
        if (is_sound_on == 1)
        {
            UART1_send(Voice_12_Arr, 6);
        }
        is_cross_wall_on = 1;
        printf("open cross wall\n");
    }
    else
    {
        if (is_sound_on == 1)
        {
            UART1_send(Voice_11_Arr, 6);
        }
        is_cross_wall_on = 0;
        printf("close cross wall\n");
    }
}

void changeAIState()
{
    if (is_ai_on == 0)
    {
        is_ai_on = 1;
        if (is_sound_on == 1)
        {
            UART1_send(Voice_14_Arr, 6);
        }
        printf("open AI\n");
    }
    else
    {
        if (is_sound_on == 1)
        {
            UART1_send(Voice_13_Arr, 6);
        }
        is_ai_on = 0;
        printf("close AI\n");
    }
}

// 设置模式按键控制
void setting_control(int dir)
{
    switch (dir)
    {
    case K1_4: // keep molde
        setKeepModeState();
        break;
    case K1_3: // add speed
        addSpeed();
        break;
    case K1_1: // minus speed
        minusSpeed();
        break;
    case K2_4: // pause or continue
        pauseGame();
        break;
    case K3_4: // restart
        restartGame();
        break;
    case K3_1: // close sound or open sound
        changeSoundState();
        break;
    case K3_2:
        changeCrossWallState(); // changeCrossWallState
        break;
    case K3_3:
        changeAIState(); // changeAIState
        break;
    default:
        break;
    }
}

// 蛇吃到食物
void eatfood()
{
    if (snake_arr[0][0] == food_pox_x && snake_arr[0][1] == food_pox_y)
    {
        printf("eatfood\n");
        tail_grow_state = 1;
        if (is_sound_on == 1)
        {
            buzzWorkOnce();
        }
        food_exist = 0;
        all_score += (110 - delay_count) / 10;
        Score_To_Arr();
        update_oled_mess();
    }
}

uint8_t dzBuffer[][32];
U16 ledTimer;
void userInit(void)
{
    gpioWrite(dz595_OE_port, dz595_OE_pin, HIGH); // close the DZ595 output
    gpioWrite(PL, 1, HIGH);                       // Enable ESP32
}
#define SET_DS() gpioWrite(PB, 2, HIGH)
#define CLR_DS() gpioWrite(PB, 2, LOW)
#define SHCLK()            \
    gpioWrite(PB, 1, LOW); \
    gpioWrite(PB, 1, HIGH)

void dzSendBit(uint8_t data, uint8_t posit)
{
    if (data & BIT(posit))
    {
        SET_DS();
    }
    else
    {
        CLR_DS();
    }
    SHCLK();
}
void segSelect(char index)
{
    PORTA &= 0xf0;
    PORTA |= index;
}
int segIndex, dzIndex;

void interrupt_1ms(void)
{
    if (is_Lcd_Run == 0)
    {
        noneAniDisplay();
    }
    //  segDisplay();
}

void noneAniDisplay(void)
{
    char *p = &zdhz[0][0];
    gpioWrite(dz595_OE_port, dz595_OE_pin, HIGH);
    spitransferByte(zdhz[1][dzIndex + 16]);
    spitransferByte(zdhz[1][dzIndex]);
    spitransferByte(zdhz[0][dzIndex + 16]);
    spitransferByte(zdhz[0][dzIndex]);
    DZ_ST_CLK();
    segSelect(dzIndex);
    gpioWrite(dz595_OE_port, dz595_OE_pin, LOW);
    dzIndex++;
    if (dzIndex > 15)
        dzIndex = 0;
}

// 蜂鸣器响应函数
void buzzWorkByCount(void)
{
    if (buzz_count_double == 0)
        return;

    if (buzz_count_double % (two_buzz_count_need / 2) == 0)
    {
        if (is_sound_on == 1)
        {
            printf("buzz\n");
            // buzzWorkOnce();
        }
        //  printf("+++:%d\n",buzz_count_double);
    }
    // printf("---:%d\n",buzz_count_double);
    buzz_count_double--;
}

// 设置停靠模式
void setKeepModeState(void)
{

    if (isKeepMolde == 0)
    {
        isOnce = 1;
        if (is_sound_on == 1)
        {
            UART1_send(Voice_07_Arr, 6);
        }

        isKeepMolde = 1;
        printf("keep mode on\n");
    }
    else
    {
        if (is_sound_on == 1)
        {
            UART1_send(Voice_08_Arr, 6);
        }

        isKeepMolde = 0;
        printf("keep mode off\n");
    }
}

// AI极速测试函数
void AI_TopSpeed_Test()
{
    is_ai_on = 1;
    delay_count = 1;
    is_sound_on = 0;
    printf("open ai topspeed test\n");
}

int segIndex, dzIndex;
// 显示数码管 计算分数
void segDisplay(void)
{
    gpioWrite(seg595_OE_port, seg595_OE_pin, HIGH);
    spitransferByte(Led_7[Disp_data[segIndex]]);
    gpioWrite(seg595_ST_port, seg595_ST_pin, LOW);
    gpioWrite(seg595_ST_port, seg595_ST_pin, HIGH);
    segSelect(segIndex);
    gpioWrite(seg595_OE_port, seg595_OE_pin, LOW);
    segIndex++;
    if (segIndex > 3)
        segIndex = 0;
}

// 定点降速调试函数
void point_slow_speed_test(int snake_len_point)
{
    if (snake_len_point == snake_len)
    {
        delay_count = 100;
    }
}

void update_oled_mess()
{
    OLED_Clear();
    // 输出总分二字
    OLED_ShowCHinese(10, 2, 7);
    OLED_ShowCHinese(30, 2, 8);
    OLED_ShowChar(50, 2, ':');
    OLED_ShowChar(70, 2, Disp_data[0] + '0');
    OLED_ShowChar(80, 2, Disp_data[1] + '0');
    OLED_ShowChar(90, 2, Disp_data[2] + '0');
    OLED_ShowChar(100, 2, Disp_data[3] + '0');

    OLED_ShowCHinese(10, 5, 9);
    OLED_ShowCHinese(30, 5, 10);
    OLED_ShowChar(50, 5, ':');
    OLED_ShowChar(70, 5, snake_len / 100 % 10 + '0');
    OLED_ShowChar(80, 5, snake_len / 10 % 10 + '0');
    OLED_ShowChar(90, 5, snake_len % 10 + '0');
}

int main(void)
{
    char test[] = {0xAA, 0x02, 0x00, 0xAC};
    int temp;
    int i = 0, j = 0;
    uint8_t keyValue;
    boardInit();
    userInit();
    UART1_send(Voice_20_Arr, 6);
    // printf("Mega2560 Test!\r\n");
    LCD_RESET();
    LCD_Init();
    main_test();

    while (lcd_run_count > 0)
    {
        lcd_run_count--;
    }

    OLED_Init();

    update_oled_mess();

    init_Snake();
    // AI_TopSpeed_Test();

    UART1_send(Voice_01_Arr, 6);

    is_Lcd_Run = 0;

    while (1)
    {
        keyBoard_process();
        keyValue = keyBoard_read();
        if ((snake_alive_normal == 1 || isKeepMolde == 1) && isRunning == 1)
        {
            if (food_exist == 0)
            {
                randomFood();
                food_exist = 1;
            }

            if (is_Arrive_Delay_count() == 1)
            {
                move_Opt();
            }
            // point_slow_speed_test(98);
            move_control(keyValue);

            eatfood();
            now_count++;
            render_Screen();
        }
        board_process();
        setting_control(keyValue);
        buzzWorkByCount();
    }
    return 0;
}
